package com.juzipi.demo.shiro;


import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.juzipi.demo.exception.CustomException;
import com.juzipi.demo.tools.Result;
import com.juzipi.demo.utils.JwtUtil;
import com.juzipi.demo.utils.RedisUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

//自定义 JWT过滤器对token处理
public class JWTFilter extends BasicHttpAuthenticationFilter {


    //是否允许访问
    //如果带有token则对token检查，没有就暂时通过
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        System.out.println("====================> isAccessAllowed");
        //判断用户是否想要登入
        try {
            executeLogin(request, response);
            return true;
        } catch (Exception e) {
            responseError(response, "登陆失败");
            return false;
        }
    }


//    //判断是否想要登录
//    @Override
//    protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
//        System.out.println("=======================> isLoginAttempt");
//        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
//        String token = httpServletRequest.getHeader("token");
//        //不为空就返回true
//        return StringUtils.isNotBlank(token);
//    }


    /**
     * 直接返回response信息
     *
     * @param response
     * @param message
     */
    private void responseError(ServletResponse response, String message) {
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        httpResponse.setStatus(400);
        httpResponse.setCharacterEncoding("UTF-8");
        httpResponse.setContentType("application/json;charset=UTF-8");
        PrintWriter writer = null;
        try {
            writer = httpResponse.getWriter();
            Result result = Result.fail(400, message);
            writer.append(JSONObject.toJSONString(result));
        } catch (IOException e) {
            throw new CustomException("直接返回Response信息出现IOException异常:" + e.getMessage());
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }


    /**
     * isAccessAllowed 为 false时调用，验证失败
     *
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        System.out.println("=======================> onAccessDenied");
        this.sendChallenge(request, response);
        responseError(response, "token验证失败");
        return false;
    }


    /**
     * shiro 验证成功时调用
     * @param token
     * @param subject
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
        System.out.println("========================> onLoginSuccess");
        String jwtToken = (String) token.getPrincipal();
        if (StringUtils.isNotBlank(jwtToken)) {
            try {
                if (JwtUtil.verify(jwtToken)) {
                    //判断redis是否存在对应的 refreshToken
                    String username = JwtUtil.getUsername(jwtToken);
                    Long currentTime = JwtUtil.getCurrentTime(jwtToken);
                    if (RedisUtil.hasKey(username)) {
                        Long currentTimeMillisRedis = (Long) RedisUtil.get(username);
                        //如果当前时间和redis里的对应就直接返回true
                        return currentTimeMillisRedis.equals(currentTime);
                    }
                }
                return false;
            } catch (Exception e) {
                Throwable throwable = e.getCause();
                System.out.println("token验证" + e.getClass());
                if (e instanceof TokenExpiredException) {
                    if (refreshToken(request, response)) {
                        return true;
                    } else {
                        return false;
                    }
                }
            }
        }
        return true;
    }





//    //执行登录
//    @Override
//    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
//        System.out.println("============================> executeLogin");
//        //拿到当前Header中Authorization的AccessToken(Shiro中getAuthzHeader方法已经实现)
//        JWTToken token = new JWTToken(getAuthzHeader(request));
//        //提交给UserRealm进行认证，如果错误他会抛出异常并被捕获
//        getSubject(request, response).login(token);
//
//        return true;
//
//    }


//    @Override
//    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
//        HttpServletRequest httpServletRequest= (HttpServletRequest) request;
//        HttpServletResponse httpServletResponse= (HttpServletResponse) response;
//        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())){
//            httpServletResponse.setStatus(HttpStatus.OK.value());
//        }
//
//        //如果不带token，不去验证shiro
//        if (!isLoginAttempt(request,response)){
//            responseError(httpServletResponse,"没有token");
//            return false;
//        }
//        return super.preHandle(request,response);
//    }



    /**
     * 创建shiro token
     * @param request
     * @param response
     * @return
     */
    @Override
    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
        System.out.println("===========================> createToken");
        String token = ((HttpServletRequest) request).getHeader("token");
        if (token != null) {
            return new JWTToken(token);
        }
        return null;
    }



    //刷新token
    private boolean refreshToken(ServletRequest request, ServletResponse response) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        String token = httpServletRequest.getHeader("token");
        String username = JwtUtil.getUsername(token);
        Long currentTime = JwtUtil.getCurrentTime(token);
        //判断redis中refreshToken是否存在
        if (RedisUtil.hasKey(username)) {
            //redis中refreshToken存在，获取refreshToken的时间戳
            Long currentTimeMillisRedis = (Long) RedisUtil.get(username);
            if (currentTimeMillisRedis.equals(currentTime)) {
                //获取当前最新时间戳
                long currentTimeMillis = System.currentTimeMillis();
                RedisUtil.set(username, currentTimeMillis, JwtUtil.REFRESH_EXPIRE_TIME);
                //刷新token，设置时间戳为当前最新时间戳
                token = JwtUtil.getToken(username, currentTimeMillis);
                httpServletResponse.setHeader("Authorization", token);
                httpServletResponse.setHeader("Access-Control-Expose-Headers", "Authorization");
                return true;
            }
        }
        return false;

    }
}




